package cn.org.donald.sensitive.factory;

import cn.org.donald.sensitive.model.FactoryEnum;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.colors.ColorConstants;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.*;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor;
import com.itextpdf.kernel.pdf.canvas.parser.listener.IPdfTextLocation;
import com.itextpdf.kernel.pdf.canvas.parser.listener.RegexBasedLocationExtractionStrategy;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Donald
 * @since 2023-11-10 17:27:48
 **/
public class PdfFindSensitive extends IFindSensitive {

    public PdfFindSensitive(Path filePath, FactoryEnum factoryEnum) {
        super(filePath, factoryEnum);
    }

    @Override
    public List<String> getSensitiveString(List<String> ruleRegexList) {
        Path filePath = super.getFilePath();
        try (PDDocument pdDocument = PDDocument.load(filePath.toFile())) {
            PDFTextStripper pdfTextStripper = new PDFTextStripper();
            String text = pdfTextStripper.getText(pdDocument);
            return super.findSensitiveInString(ruleRegexList, text).collect(Collectors.toList());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void replace(List<String> ruleRegexList, Path destPath) {
        WriterProperties writerProperties = new WriterProperties();
        writerProperties.setStandardEncryption(
                null,
                null,
                EncryptionConstants.ALLOW_PRINTING
                        | EncryptionConstants.ALLOW_ASSEMBLY | EncryptionConstants.ALLOW_DEGRADED_PRINTING
                        | EncryptionConstants.ALLOW_FILL_IN | EncryptionConstants.ALLOW_MODIFY_ANNOTATIONS
                        | EncryptionConstants.ALLOW_MODIFY_CONTENTS
                ,
                EncryptionConstants.DO_NOT_ENCRYPT_METADATA);
        try (PdfReader reader = new PdfReader(super.getFilePath().toFile());
             OutputStream outputStream = Files.newOutputStream(destPath, StandardOpenOption.WRITE);
             PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(outputStream, writerProperties))) {
            String regex = String.join("|", ruleRegexList);
            for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {
                PdfFont font;
                try {
                    font = PdfFontFactory.createFont("./data/SIMSUN.TTF", PdfEncodings.IDENTITY_H);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                PdfPage page = pdfDocument.getPage(i);
                RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(regex);
                PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(strategy);
                canvasProcessor.processPageContent(page);
                Collection<IPdfTextLocation> resultantLocations = strategy.getResultantLocations();
                PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), pdfDocument);
                pdfCanvas.setLineWidth(0.5f);
                for (IPdfTextLocation location : resultantLocations) {
                    Rectangle rectangle = location.getRectangle();
                    pdfCanvas.rectangle(rectangle);
                    pdfCanvas.saveState();
                    //用白色背景覆盖原本的字体
                    pdfCanvas.setFillColor(ColorConstants.WHITE);
                    //覆盖的时候y + 0.35   填充字体的时候 + 1.5 主要就是避免覆盖占位符下面的线
                    pdfCanvas.rectangle(rectangle.getX(), rectangle.getY() + 0.35, rectangle.getWidth(), rectangle.getHeight());
                    pdfCanvas.fill();
                    pdfCanvas.restoreState();

                    //填充新内容
                    pdfCanvas.beginText();
                    pdfCanvas.setFontAndSize(font, rectangle.getHeight());
                    pdfCanvas.setTextMatrix(rectangle.getX(), rectangle.getY() + 1.5f);
                    String text = location.getText();
                    @SuppressWarnings("all")
                    String replace = text.replaceAll(".", "*");
                    pdfCanvas.newlineShowText(replace);
                    pdfCanvas.endText();
                }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
